package org.xxpay.pay.channel.nps;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;
import org.xxpay.common.http.HttpRequestTemplate;
import org.xxpay.common.util.DateUtils;
import org.xxpay.common.util.Util;
import org.xxpay.common.util.XML;
import org.xxpay.common.util.sign.SignUtils;
import org.xxpay.common.util.sign.encrypt.Base64;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.channel.nps.util.EncryptUtil;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

@Service
public class NpsPaymentService extends BasePayment {

    private final static String logPrefix = "【NPS】";
    // 下单地址
    public static final String ORDER_CREATE_STR = "/pay.cgi";
    // 查单地址
    private final static String ORDER_QUERY_STR = "/query.cgi";

    @Override
    public String getChannelName() {
        return NpsConfig.CHANNEL_NAME;
    }

    @Override
    public JSONObject pay(PayOrder payOrder) {
        String channelId = payOrder.getChannelId();
        JSONObject retObj;
        switch (channelId) {
            case NpsConfig.CHANNEL_NAME_NPS_QUICK:
                retObj = doOrderQuickReq(payOrder);
                break;
            case NpsConfig.CHANNEL_NAME_NPS_UNION_QR:
                retObj = doOrderQRReq(payOrder);
                break;
            case NpsConfig.CHANNEL_NAME_NPS_JD_QR:
                retObj = doOrderQRReq(payOrder);
                break;
            default:
                retObj = buildRetObj(PayConstant.RETURN_VALUE_FAIL, "不支持的渠道[channelId="+channelId+"]");
                break;
        }
        return retObj;
    }
    /**
     * 快捷下单实现
     * @param payOrder
     * @return
     */
    private JSONObject doOrderQuickReq(PayOrder payOrder){
        NpsConfig npsConfig = new NpsConfig(getPayParam(payOrder));
        Map<String, Object> params = Maps.newLinkedHashMap();
        setQuickParam(params, payOrder, npsConfig);
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        String restData = requestTemplate.postForObject(getReqUrl(npsConfig.getRequestUrl(),ORDER_CREATE_STR), params, String.class);
        _log.info("{}请求响应参数：{}", logPrefix, restData);
        JSONObject origin = XML.toJSONObject(restData);
        String payUrl = null;
        JSONObject retObj = new JSONObject();
        if (origin.get("RESP_CODE").equals("0000")){
            payUrl = origin.getString("PAY_INFO");
            String decPayUrl = null;
            try {
                byte[] decodeBase64KeyBytes = Base64.decode(payUrl);
                decPayUrl = new String(decodeBase64KeyBytes, SignUtils.CHARSET_UTF8);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            _log.info("{}请求响应解密Url：{}", logPrefix, decPayUrl);
            return buildPayResultOfForm(retObj, payOrder, decPayUrl);
        }
        retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
        retObj.put(PayConstant.RESULT_PARAM_ERRDES, origin.get("RESP_DESC"));
        return retObj;
    }

    /**
     * 扫码下单实现
     * @param payOrder
     * @return
     */
    private JSONObject doOrderQRReq(PayOrder payOrder){
        NpsConfig npsConfig = new NpsConfig(getPayParam(payOrder));
        Map<String, Object> params = Maps.newLinkedHashMap();
        setQRParam(params, payOrder, npsConfig);
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        String restData = requestTemplate.postForObject(getReqUrl(npsConfig.getRequestUrl(),ORDER_CREATE_STR), params, String.class);
        _log.info("{}请求响应参数：{}", logPrefix, restData);
        JSONObject origin = XML.toJSONObject(restData);
        String payUrl = null;
        JSONObject retObj = new JSONObject();
        if (origin.get("RESP_CODE").equals("0000")){
            payUrl = origin.getString("CODE_URL");
            return buildPayResultOfCodeURL(retObj, payOrder, payUrl);
        }
        retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
        retObj.put(PayConstant.RESULT_PARAM_ERRDES, origin.get("RESP_DESC"));
        return retObj;
    }

    /**
     * 构建快捷请参数
     * @param params
     * @param payOrder
     * @param npsConfig
     */
    private void setQuickParam(Map<String, Object> params, PayOrder payOrder, NpsConfig npsConfig) {
        params.put("ORDER_ID", payOrder.getPayOrderId());
        params.put("ORDER_AMT", Util.conversionYuanAmount(payOrder.getAmount()));
        params.put("ORDER_TIME", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        params.put("USER_TYPE", "02");
        params.put("USER_ID", npsConfig.getMchId());
        params.put("SIGN_TYPE", "03");
        params.put("BUS_CODE", npsConfig.getPayMode());
        params.put("CCT", "CNY");
        params.put("PAY_TYPE", "01");
        params.put("CARD_TYPE", "01");
        params.put("BANK_CODE", "");
        params.put("CARD_NO", "");
        params.put("GOODS_NAME", "手机充值");
        params.put("GOODS_DESC", "网上充值");
        params.put("BG_URL", payConfig.getNotifyUrl(getChannelName()));
        params.put("PAGE_URL", payOrder.getReturnUrl());
        params.put("SIGN", getQuicksign(params, npsConfig.getPrivateKey()));
        _log.info("{}请求参数：{}", logPrefix, params.toString());
    }

    /**
     * 构建二维码请参数
     * @param params
     * @param payOrder
     * @param npsConfig
     */
    private void setQRParam(Map<String, Object> params, PayOrder payOrder, NpsConfig npsConfig) {
        params.put("ORDER_ID", payOrder.getPayOrderId());
        params.put("ORDER_AMT", Util.conversionYuanAmount(payOrder.getAmount()));
        params.put("ORDER_TIME", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        params.put("USER_TYPE", "02");
        params.put("USER_ID", npsConfig.getMchId());
        params.put("SIGN_TYPE", "03");
        params.put("BUS_CODE", npsConfig.getPayMode());
        params.put("CCT", "CNY");
        params.put("BG_URL", payConfig.getNotifyUrl(getChannelName()));
        params.put("PAGE_URL", payOrder.getReturnUrl());
        params.put("GOODS_NAME", payOrder.getSubject());
        params.put("GOODS_DESC", payOrder.getBody());
        params.put("SIGN", getQRsign(params, npsConfig.getPrivateKey()));
        _log.info("{}请求参数：{}", logPrefix, params.toString());
    }
    /**
     * 签名
     * @param params
     * @param key
     * @return
     */
    private String getQuicksign (Map<String, Object> params, String key) {
        String signStr= "ORDER_ID=" + params.get("ORDER_ID")
                + "&ORDER_AMT=" + params.get("ORDER_AMT")
                + "&ORDER_TIME=" + params.get("ORDER_TIME")
                + "&USER_TYPE=" + params.get("USER_TYPE")
                + "&USER_ID=" + params.get("USER_ID")
                + "&SIGN_TYPE=" + params.get("SIGN_TYPE")
                + "&BUS_CODE=" + params.get("BUS_CODE")
                + "&CCT=" + params.get("CCT")
                + "&PAY_TYPE=" + params.get("PAY_TYPE")
                + "&CARD_TYPE="+ params.get("CARD_TYPE")
                + "&BANK_CODE=" + params.get("BANK_CODE")
                + "&CARD_NO="+ params.get("CARD_NO")
                + "&"+key;
        _log.info("{}快捷签名结果:{}", logPrefix, signStr);
        String sign= EncryptUtil.MD5(EncryptUtil.MD5(signStr, 1).toUpperCase()+key,0).toUpperCase();
        _log.info("{}快捷签名结果:{}", logPrefix, sign);
        return sign;
    }

    /**
     * 查询订单
     * @param payOrder
     * @return
     */
    @Override
    public JSONObject query(PayOrder payOrder) {
        NpsConfig npsConfig = new NpsConfig(getPayParam(payOrder));
        Map<String, Object> params = Maps.newHashMap();
        params.put("ORDER_ID", payOrder.getPayOrderId());
        params.put("USER_TYPE", "02");
        params.put("USER_ID", npsConfig.getMchId());
        params.put("SIGN_TYPE", "03");
        String signStr= "ORDER_ID=" + params.get("ORDER_ID")
                +"&USER_TYPE=" + params.get("USER_TYPE")
                +"&USER_ID=" + params.get("USER_ID")
                +"&SIGN_TYPE=" + params.get("SIGN_TYPE")
                + "&"+ npsConfig.getPrivateKey();

        System.out.println("支付请求："+signStr);
        String SIGN= EncryptUtil.MD5(EncryptUtil.MD5(signStr, 1).toUpperCase()+npsConfig.getPrivateKey(),0).toUpperCase();
        params.put("SIGN", SIGN);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        String restData = requestTemplate.postForObject(getReqUrl(npsConfig.getRequestUrl(),ORDER_QUERY_STR), params, String.class);
        _log.info("{}代付查询请求响应参数：{}", logPrefix, restData);
        JSONObject origin = XML.toJSONObject(restData);
        JSONObject retObj = buildRetObj();
        if (origin.get("STATUS").equals("1")){
            retObj.put("isSuccess", true);
            retObj.put("transOrderId", origin.getString("ORDER_ID"));
            retObj.put("channelObj", origin);
            if (origin.get("RESP_CODE").equals("0000")){
                //0：订单生成，1：支付中，-1：支付失败，2：支付成功，3：业务处理完成，-2：订单过期
                // 1. 处理中 2. 成功 3. 失败
                retObj.put("status", 2);
                return retObj;
            }
            retObj.put("status", 1);
            return retObj;
        }
        retObj.put("status", 1);
        retObj.put("channelObj", origin);
        retObj.put(PayConstant.RESULT_PARAM_ERRDES, "查单失败[" + origin.getString("RESP_DESC") + "]");
        retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
        return retObj;
    }

    /**
     * 签名
     * @param params
     * @param key
     * @return
     */
    private String getQRsign (Map<String, Object> params, String key) {
        String signStr= "ORDER_ID="+params.get("ORDER_ID")
                +"&ORDER_AMT="+params.get("ORDER_AMT")
                +"&ORDER_TIME="+params.get("ORDER_TIME")
                +"&USER_TYPE="+params.get("USER_TYPE")
                +"&USER_ID="+params.get("USER_ID")
                +"&SIGN_TYPE="+params.get("SIGN_TYPE")
                +"&BUS_CODE=" +params.get("BUS_CODE")
                +"&CCT="+params.get("CCT") + "&"+key;
        String sign= EncryptUtil.MD5(EncryptUtil.MD5(signStr, 1).toUpperCase()+key,0).toUpperCase();
       _log.info("{}扫码签名结果:{}", logPrefix, sign);
        return sign;
    }


}
